package com.tsx.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;
import java.util.Objects;

@Slf4j
public final class SpELParserUtils {

    private static final String EXPRESSION_PREFIX = "#{";
    private static final String EXPRESSION_SUFFIX = "}";
    private static final ExpressionParser expressionParser = new SpelExpressionParser();
    private static final DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();


    private SpELParserUtils() {
    }

    /**
     * 通过方法参数和参数值t解析SpEL表达式
     *
     * @param args           方法参数值
     * @param paramNames     方法参数名
     * @param spELExpression SpEL表达式
     * @param clz            返回结果类型
     * @param <T>            返回类型泛型
     * @return 解析结果
     */
    public static <T> T parse(Object[] args, String[] paramNames,
                              String spELExpression, Class<T> clz) {
        EvaluationContext context = new StandardEvaluationContext();
        // 设置上下文变量
        for (int i = 0; i < paramNames.length; i++) {
            context.setVariable(paramNames[i], args[i]);
        }
        try {
            Expression expression = parseExpression(spELExpression);
            return expression.getValue(context, clz);
        } catch (Exception e) {
            log.error("解析SpEL表达式失败: {}", spELExpression, e);
            return null;
        }
    }

    /**
     * 通过方法和参数值解析SpEL表达式
     *
     * @param method         方法
     * @param args           参数值
     * @param spELExpression SpEl表达式
     * @param clz            返回结果类型
     * @param <T>            返回类型泛型
     * @return 解析结果
     */
    public static <T> T parse(Method method, Object[] args,
                              String spELExpression, Class<T> clz) {
        String[] parameterNames = Objects.requireNonNull(parameterNameDiscoverer.getParameterNames(method));
        return parse(args, parameterNames, spELExpression, clz);
    }

    /**
     * 解析表达式
     */
    private static Expression parseExpression(String spELExpression) {
        if (spELExpression.startsWith(EXPRESSION_PREFIX) &&
                spELExpression.endsWith(EXPRESSION_SUFFIX)) {
            return expressionParser.parseExpression(spELExpression, new TemplateParserContext());
        }
        return expressionParser.parseExpression(spELExpression);
    }
}
